package org.funsciencewithyourcomputer.client;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Words {

	List<String> lines = new ArrayList<String>();

	Dictionary dictionary;

	public static final int N_Lines = 7;

	public static final int N_Characters = 7;

	public static final String EMPTY_LINE = "\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0";

	public Words(Dictionary dictionary) {
		this.dictionary = dictionary;
	}

	public Words(Words words) {
		this.lines = new ArrayList<String>(words.lines);
		this.dictionary = words.dictionary;
	}

	public boolean addLine(String line) {
		removeEmptyLinesAtTop(lines);
		if (lines.size() >= N_Lines)
			return false;
		lines.add(0, line);
		return true;
	}

	/**
	 * Remove lines with no character (or only with spaces) at the top. They
	 * result from user forming words and don't prevent us from pushing new
	 * lines.
	 */
	private void removeEmptyLinesAtTop(List<String> lines) {
		while (lines.size() > 0) {
			if (lines.get(lines.size() - 1).trim().length() == 0)
				lines.remove(lines.size() - 1);
			else
				break;
		}
	}

	public String toString() {
		String result = "";
		List<String> lines = new ArrayList<String>(this.lines);
		for (int i = lines.size(); i < N_Lines; i++)
			result += EMPTY_LINE + "\n";
		Collections.reverse(lines);
		for (String line : lines)
			result += line + "\n";
		result = result.substring(0, result.length() - 1);
		return result;
	}

	public int removeAndFall(String letters) {
		int result = remove(letters);
		if (result != 0)
			lines = fall(lines);
		return result;
	}

	public int remove(String letters) {
		if (!dictionary.isWord(letters))
			return 0;
		Words words = new Words(this);
		// Remove all occurrences along rows
		int h = remove(letters, true);
		// Remove all occurrences along columns (even reusing letters already used
		// on rows, reason why we use a copy
		int v = words.remove(letters, false);
		// Merge in
		if (v > 0)
			remove(words);
		return h+v;
	}

	/**
	 * Remove the blanks from the given instance
	 */
	private void remove(Words words) {
		int lineNumber = 0;
		for (String line : words.lines) {
			int characterIndex = 0;
			for (char letter : line.toCharArray()) {
				if (letter == ' ') {
					String toReplace = lines.get(lineNumber);
					if (toReplace.charAt(characterIndex) != ' ') {
						toReplace = Dictionary.replace(toReplace,
								characterIndex, " ");
						lines.set(lineNumber, toReplace);
					}
				}
				characterIndex++;
			}
			lineNumber++;
		}
	}

	private int remove(String letters, boolean horizontal) {
		if (horizontal) {
			return remove(letters, lines);
		} else {
			List<String> rotate = rotate(lines);
			int result = remove(letters, rotate);
			lines = rotate(rotate);
			return result;
		}
	}

	private int remove(String letters, List<String> lines) {
		int result = 0;
		if (!dictionary.isWord(letters))
			return result;
		int index = 0;
		String[] resultingLine = new String[1];
		for (String line : new ArrayList<String>(lines)) {
			int[] indeces = Dictionary.getPositions(line, letters,
					resultingLine);
			if (indeces != null) {
				lines.set(index, resultingLine[0]);
				resultingLine[0] = null;
				result += indeces.length;
			}
			index++;
		}
		return result;
	}

	private static List<String> rotate(List<String> lines) {
		List<String> result = new ArrayList<String>();
		while (lines.size() > 0 && result.size() < lines.get(0).length())
			result.add("");
		for (String line : lines) {
			int i = 0;
			for (char character : line.toCharArray()) {
				result.set(i, result.get(i) + "" + character);
				i++;
			}
		}
		return result;
	}

	public List<String> fall(List<String> lines) {
		lines = rotate(lines);
		// remove all spaces
		for (int i = 0; i < lines.size(); i++) {
			String oldLine = lines.get(i);
			String newLine = oldLine.replaceAll(" ", "");
			while (newLine.length() < oldLine.length())
				newLine += " ";
			lines.set(i, newLine);
		}
		return rotate(lines);
	}

	public List<int[]> highlightIndeces(String word, boolean horizontal) {
		Words copy = new Words(this);
		if (!horizontal)
			copy.lines = rotate(copy.lines);
		List<String> lines = copy.lines;
		List<int[]> result = new ArrayList<int[]>();
		int total = 0;
		String[] resultingLine = new String[1];
		for (int i = 0; i < lines.size(); i++) {
			String line = lines.get(i);
			int[] indices = Dictionary.getPositions(line, word, resultingLine);
			if (indices != null) {
				lines.set(i, resultingLine[0]);
				convert(indices, i, line.length(), lines.size(), horizontal);
				result.add(indices);
			}
			total += horizontal ? line.length() : lines.size();
		}
		return result;
	}

	public boolean isHot(int row, int column, List<int[]> indeces,
			boolean horizontal) {
		int index = row * N_Characters + column;
		for (int[] array : indeces)
			for (int pos : array)
				if (pos == index)
					return true;
		return false;
	}

	public int countLetters() {
		int result = 0;
		for (String line : lines) {
			for (char character : line.toCharArray()) {
				if (character != ' ' && character != '\u00A0')
					result++;
			}
		}
		return result;
	}

	static void convert(int[] columns, int row, int nRows, int nColumns,
			boolean horizontal) {
		for (int i = 0; i < columns.length; i++) {
			if (horizontal)
				columns[i] = columns[i] + row * nRows;
			else {
				columns[i] = row + columns[i] * nColumns;
			}
		}
	}

}
